package com.ezops.controller;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.ezops.dao.facade.DataTransferFacade;
import com.ezops.dao.facade.IReportDataTransferFacade;
import com.ezops.dao.generics.search.Search;
import com.ezops.models.Report;
import com.ezops.models.User;
import com.ezops.models.UserGroup;
import com.ezops.util.PDFReader;
import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
public class ReportsManagerController {

	final static Logger logger = LoggerFactory
			.getLogger(ReportsManagerController.class);

	@Autowired
	private IReportDataTransferFacade facade;

	@Autowired
	@Qualifier("UserDataTransferFacade")
	private DataTransferFacade<User> userFacade;

	@Autowired
	@Qualifier("UserGroupDataTransferFacade")
	private DataTransferFacade<UserGroup> userGroupFacade;

	/**
	 * Get ReportBy Id as a PDF
	 * 
	 * @param jsonbody
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(method = RequestMethod.GET, value = "/getReportByIdAsPDF/{reportid}", produces = "image/jpg")
	@ResponseBody
	public ResponseEntity<byte[]> getReporyAsPDF(
			@PathVariable("reportid") String reportId,
			HttpServletRequest request, HttpServletResponse response) {

		final HttpHeaders responseHeaders = new HttpHeaders();
		responseHeaders.setContentType(MediaType.IMAGE_JPEG);

		byte[] rawImg = null;
		try {

			// Finds the user by id
			Search searchCriteria = new Search();
			searchCriteria.addFilterEqual("reportId", reportId);
			Report foundReport = facade.searchUnique(searchCriteria);
			if (foundReport == null) {
				response.sendError(HttpServletResponse.SC_BAD_REQUEST,
						"Report not Found for id[ " + reportId + "]");
				return new ResponseEntity<byte[]>(rawImg, responseHeaders,
						HttpStatus.BAD_REQUEST);
			}

			String fullPathToFileName = foundReport.getFileLocation() + "\\"
					+ foundReport.getFileName();
			File fileToLoad = new File(fullPathToFileName);
			BufferedInputStream fileInputStream = new BufferedInputStream(
					FileUtils.openInputStream(fileToLoad));
			// =====================================================================================
			List<byte[]> byteList = null;
			String destination = "C:/temp";
			// System.out.println("Input Report file Name  ==>" +
			// fullPathToFileName);
			// 1- Extract images from PDF.Total Byte array in PDF file
			PDFReader pdfReader = new PDFReader();
			// Requirement :- If report other then PDF e.g. excel (xls/xlsx)
			// file then just open blank image.
			String defaultpath = foundReport.getFileLocation()
					+ "\\logo-pdf.jpg";// No_Image.jpeg";

			if ("pdf".equals(FilenameUtils.getExtension(fullPathToFileName))) {
				byteList = pdfReader.extractImages(fullPathToFileName,
						foundReport.getFileName(), destination);
			} else {
				// Convert File to CSV format
				// For UI testing CSV file path should be as per dummy data
				// C:\Program Files (x86)\Apache Software Foundation\Tomcat
				// 7.0\webapps\sampledata
				String outputFile = foundReport.getFileLocation()
						+ "\\"
						+ FilenameUtils.removeExtension(foundReport
								.getFileName()) + ".csv";// +FilenameUtils.getExtension(fullPathToFileName);
				convertFileToCSV(outputFile, fullPathToFileName);
				defaultpath = foundReport.getFileLocation()
						+ "\\logo-excel.jpg";// No_Image.jpeg";
			}
			if (byteList != null && byteList.size() > 0) {
				// System.out.println("Total Images extracted from PDF file ==>"
				// + byteList.size());
				rawImg = byteList.get(0);// Assuming currently PDF have only one
											// image//
				// System.out.println("Raw Image ==>" + rawImg);
			} else {

				String defaulImageLocation = "C:\\Program Files (x86)\\Apache Software Foundation\\Tomcat 7.0\\webapps";

				// setting default images depending on the category
				if (foundReport.getCategory().equalsIgnoreCase("risk")) {
					// defaultpath= foundReport.getFileLocation()+"\\risk.jpg";
					defaultpath = defaulImageLocation + "\\risk.jpg";

				} else if (foundReport.getCategory().equalsIgnoreCase("aging")) {
					// defaultpath= foundReport.getFileLocation()+"\\aging.jpg";
					defaultpath = defaulImageLocation + "\\aging.jpg";

				} else if (foundReport.getCategory().equalsIgnoreCase("poscp")) {
					// defaultpath= foundReport.getFileLocation()+"\\poscp.jpg";
					defaultpath = defaulImageLocation + "\\poscp.jpg";

				} else if (foundReport.getCategory().equalsIgnoreCase("posprd")) {
					// defaultpath=
					// foundReport.getFileLocation()+"\\posprd.jpg";
					defaultpath = defaulImageLocation + "\\posprd.jpg";

				} else if (foundReport.getCategory().equalsIgnoreCase("cash")) {
					// defaultpath= foundReport.getFileLocation()+"\\cash.jpg";
					defaultpath = defaulImageLocation + "\\cash.jpg";

				}

				File logo = new File(defaultpath);
				rawImg = FileUtils.readFileToByteArray(logo);
			}
			// If no image in PDF file then send raw blank image to UI for
			// rendering blank image
			// =====================================================================================

			// response.setContentLength((int) fileToLoad.length());
			// response.setStatus(HttpServletResponse.SC_OK);
			// response.setContentType("application/pdf");
			// IOUtils.copy(fileInputStream, response.getOutputStream());
			return new ResponseEntity<byte[]>(rawImg, responseHeaders,
					HttpStatus.OK);

		} catch (Throwable e) {
			e.printStackTrace();
			logger.error(e.getMessage());
			response.setStatus(500);
			// jsonText = "{\"ERROR_CODE\":\""+e.getMessage()+"\"}";
			// Set the exception and send it back to the caller

		} finally {
		}

		return new ResponseEntity<byte[]>(rawImg, responseHeaders,
				HttpStatus.OK);
	}

	/**
	 * Get ReportBy Id as a CSV
	 * 
	 * @param jsonbody
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(method = RequestMethod.GET, value = "/getReportByIdAsCSV/{reportid}")
	@ResponseBody
	public String getReportAsCSV(@RequestBody String jsonbody,
			@PathVariable("reportid") String reportId,
			HttpServletRequest request, HttpServletResponse response) {

		String jsonText = "";

		try {

			Search searchCriteria = new Search();
			searchCriteria.addFilterEqual("reportId", reportId);
			Report foundReport = facade.searchUnique(searchCriteria);
			if (foundReport == null) {
				response.sendError(HttpServletResponse.SC_BAD_REQUEST,
						"Report not Found for id[ " + reportId + "]");
				return "";
			}

			String fullPathToFileName = foundReport.getFileLocation() + "\\"
					+ foundReport.getFileName();
			File fileToLoad = new File(fullPathToFileName);
			BufferedInputStream fileInputStream = new BufferedInputStream(
					FileUtils.openInputStream(fileToLoad));
			response.setContentLength((int) fileToLoad.length());
			response.setStatus(HttpServletResponse.SC_OK);
			response.setContentType("text/csv");
			IOUtils.copy(fileInputStream, response.getOutputStream());

		} catch (Throwable e) {
			e.printStackTrace();
			logger.error(e.getMessage());
			response.setStatus(500);
			jsonText = "{\"ERROR_CODE\":\"" + e.getMessage() + "\"}";
			// Set the exception and send it back to the caller

		} finally {
		}

		return jsonText;
	}

	/**
	 * Get Report Id list for a given user and optional category
	 * 
	 * @param jsonbody
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(method = RequestMethod.GET, value = "/getReportIds/{userid}/{category}")
	@ResponseBody
	public String getUserReportsIds(@RequestBody String jsonbody,
			@PathVariable("userid") String userId,
			@PathVariable("category") String category,
			HttpServletRequest request, HttpServletResponse response) {

		String jsonText = "";

		try {

			// Finds the user by id
			Search searchCriteria = new Search();
			searchCriteria.addFilterEqual("userId", userId);
			User foundUser = userFacade.searchUnique(searchCriteria);
			if (foundUser == null) {
				response.sendError(HttpServletResponse.SC_BAD_REQUEST,
						"User Not Found id[ " + userId + "]");
				return "";
			}

			System.out.println(userId + " : " + foundUser.getGroupId());
			ArrayList<Report> userReportList = new ArrayList<Report>();
			searchCriteria = new Search();
			searchCriteria.addFilterEqual("groupId", foundUser.getGroupId());

			// System.out.println("Category ===>"+ category);
			// UI send null value as "null" so treated as "null" string.So
			// convert this Object value "null" back to java null value
			if (category != null && category.trim().equals("null")) {
				category = null;
			}
			if (category != null)
				searchCriteria.addFilterEqual("category", category);
			List<Report> reportListSeq = facade.getReportListSeq();
			if (!CollectionUtils.isEmpty(reportListSeq)) {
				Report rpt = (Report) reportListSeq.get(0);
			}

			System.out.println(">>>>>>>>>>>>>." + reportListSeq);

			List<Report> reportList = facade.search(searchCriteria);

			System.out.println(">>>>>>>>>>>>>." + reportList);
			userReportList.addAll(reportListSeq);

			/**
			 * searchCriteria = new Search();
			 * searchCriteria.addFilterEqual("userId", userId); List<UserGroup>
			 * userGroupList = userGroupDTF.search(searchCriteria);
			 * 
			 * 
			 * 
			 * ArrayList<Report> userReportList = new ArrayList(); for(UserGroup
			 * userGroup: userGroupList){
			 * 
			 * 
			 * //Finds the user's resources searchCriteria = new Search();
			 * searchCriteria.addFilterEqual("groupId", foundUser.getGroupId());
			 * if(category != null) searchCriteria.addFilterEqual("category",
			 * category);
			 * 
			 * List<Report> reportList = reportDTF.search(searchCriteria);
			 * userReportList.addAll(reportList);
			 * 
			 * 
			 * 
			 * }
			 */
			ObjectMapper mapper = new ObjectMapper();
			jsonText = mapper.writeValueAsString(userReportList);
			response.setStatus(HttpServletResponse.SC_OK);
			response.setContentType("application/json");

		} catch (Throwable e) {
			e.printStackTrace();
			logger.error(e.getMessage());
			response.setStatus(500);
			jsonText = "{\"ERROR_CODE\":\"" + e.getMessage() + "\"}";
			// Set the exception and send it back to the caller

		} finally {
		}

		return jsonText;
	}

	/**
	 * 
	 * @param jsonbody
	 * @param userId
	 * @param category
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(method = RequestMethod.GET, value = "/getAllReportIds/{userid}/{category}/{fromDate}/{toDate}")
	@ResponseBody
	public String getAllUserReportsIds(@RequestBody String jsonbody,
			@PathVariable("userid") String userId,
			@PathVariable("category") String category,
			@PathVariable("fromDate") String fromDate,
			@PathVariable("toDate") String toDate, HttpServletRequest request,
			HttpServletResponse response) {

		String jsonText = "";

		try {

			// Finds the user by id
			Search searchCriteria = new Search();
			searchCriteria.addFilterEqual("userId", userId);
			User foundUser = userFacade.searchUnique(searchCriteria);
			if (foundUser == null) {
				response.sendError(HttpServletResponse.SC_BAD_REQUEST,
						"User Not Found id[ " + userId + "]");
				return "";
			}

			System.out.println(userId + " : " + foundUser.getGroupId());
			ArrayList<Report> userReportList = new ArrayList<Report>();
			searchCriteria = new Search();
			searchCriteria.addFilterEqual("groupId", foundUser.getGroupId());
			SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy");
			System.out.println(fromDate + " --- " + toDate);
			Date fromD = sdf.parse(fromDate);
			Date toD = sdf.parse(toDate);
			System.out.println(fromD + " --- " + toD);
			searchCriteria.addFilterGreaterOrEqual("asOfDate", fromD);
			searchCriteria.addFilterLessOrEqual("asOfDate", toD);

			System.out.println("Category ===>" + category);
			// UI send null value as "null" so treated as "null" string.So
			// convert this Object value "null" back to java null value
			if (category != null && category.trim().equals("null")) {
				category = null;
			}
			if (category != null)
				searchCriteria.addFilterEqual("category", category);

			List<Report> reportList = facade.search(searchCriteria);

			System.out.println(">>>>>>>>>>>>>." + reportList);
			userReportList.addAll(reportList);

			ObjectMapper mapper = new ObjectMapper();
			jsonText = mapper.writeValueAsString(userReportList);
			response.setStatus(HttpServletResponse.SC_OK);
			response.setContentType("application/json");

		} catch (Throwable e) {
			e.printStackTrace();
			logger.error(e.getMessage());
			response.setStatus(500);
			jsonText = "{\"ERROR_CODE\":\"" + e.getMessage() + "\"}";
			// Set the exception and send it back to the caller

		} finally {
		}

		return jsonText;
	}

	/***
	 * Store a document
	 */
	@RequestMapping(method = RequestMethod.POST, value = "/storeReport")
	@ResponseBody
	public String store(HttpServletRequest request,
			HttpServletResponse response,
			@RequestParam("report") String reportStoreJson,
			@RequestParam("file") MultipartFile file) {

		String jsonText = "";

		// THIS IS A HACK for the explicit use of the DEMO we will fix this with
		// proper system properties in the configuration and remove the hard
		// code location
		String storeLocation = "C:\\Program Files (x86)\\Apache Software Foundation\\Tomcat 7.0\\webapps";
		// ################################################################################################
		try {

			logger.debug("Report Store JSON :      \n" + reportStoreJson);

			ObjectMapper mapper = new ObjectMapper();
			Report newReport = mapper.readValue(reportStoreJson, Report.class);

			// Generate a new report Id
			String newReportId = RandomStringUtils.randomNumeric(6);
			newReport.setId(newReportId);
			newReport.setFileLocation(storeLocation);
			facade.save(newReport);

			// now write out the file , check if it exists first
			// might have been an error or a repost.
			String fullFileName = storeLocation + newReport.getFileName();
			File reportFileToStore = new File(fullFileName);
			if (!reportFileToStore.exists()) {

				FileOutputStream fileOutputStream = new FileOutputStream(
						reportFileToStore);
				IOUtils.copy(file.getInputStream(), fileOutputStream);
				fileOutputStream.close();
			}

		} catch (Throwable e) {
			e.printStackTrace();
			logger.error(e.getMessage());
			response.setStatus(500);
			jsonText = "{\"ERROR_CODE\":\"" + e.getMessage() + "\"}";
			// Set the exception and send it back to the caller

		} finally {
		}

		return jsonText;

	}

	// Jai- Overload store method as per request data
	/**
	 * Upload report into DB
	 * 
	 * @param request
	 * @param response
	 * @param name
	 * @param category
	 * @param groupId
	 * @param file
	 * @return
	 */
	@RequestMapping(value = "/upload", method = RequestMethod.POST)
	public @ResponseBody
	String store(HttpServletRequest request, HttpServletResponse response,
			@RequestParam("category") String category,
			@RequestParam("groupId") String groupId,
			@RequestParam("file") MultipartFile file) {

		String jsonText = "";

		// THIS IS A HACK for the explicit use of the DEMO we will fix this with
		// proper system properties in the configuration and remove the hard
		// code location
		// String storeLocation =
		// "C:\\Program Files (x86)\\Apache Software Foundation\\Tomcat 7.0\\webapps";

		// ADJUST to store in sample place CHRIS
		String storeLocation = "C:\\Program Files (x86)\\Apache Software Foundation\\Tomcat 7.0\\webapps\\EZOPSDashboardUI\\assets\\sampledata";

		// ################################################################################################
		try {

			// logger.debug("Report Store JSON :      \n"+reportStoreJson);

			// ObjectMapper mapper = new ObjectMapper();
			// Report newReport =mapper.readValue(reportStoreJson,Report.class);
			// Create new Report object from request parameters
			Report newReport = new Report();// .readValue(reportStoreJson,Report.class);
			newReport.setCategory(category);
			newReport.setGroupId(groupId);
			newReport.setFileName(file.getOriginalFilename());

			// Generate a new report Id
			String newReportId = RandomStringUtils.randomNumeric(6);
			newReport.setId(newReportId);
			newReport.setFileLocation(storeLocation);
			facade.save(newReport);

			// now write out the file , check if it exists first
			// might have been an error or a repost.
			// System.out.println(">>>>>>>>>>>>>>>>>>>"+file.getOriginalFilename());
			String fullFileName = storeLocation + "\\"
					+ file.getOriginalFilename();
			// System.out.println("Uploaded file name : "+ fullFileName);
			File reportFileToStore = new File(fullFileName);
			if (!reportFileToStore.exists()) {

				FileOutputStream fileOutputStream = new FileOutputStream(
						reportFileToStore);
				IOUtils.copy(file.getInputStream(), fileOutputStream);
				fileOutputStream.close();
			}

			response.sendRedirect(request.getContextPath() + "/referencedata");

		} catch (Throwable e) {
			e.printStackTrace();
			logger.error(e.getMessage());
			response.setStatus(500);
			jsonText = "{\"ERROR_CODE\":\"" + e.getMessage() + "\"}";
			// Set the exception and send it back to the caller

		} finally {
		}
		return "";
	}

	// Start File Conversion
	/**
	 * Convert input XSLX File To CSV
	 * 
	 * @param foundReport
	 * @param inputFilePath
	 */
	private void convertFileToCSV(String outputFilePath, String inputFilePath) {
		// Check file extension for xls & xlsx
		if ("xlsx".equals(FilenameUtils.getExtension(inputFilePath))) {
			File outputFile = new File(outputFilePath);
			System.out.println("inFile -->" + inputFilePath + " || "
					+ "outFile -->" + outputFilePath + "  isFileExist :"
					+ outputFile.exists());
			// Check if file already converted then donot convert same file
			// again..
			// if (!outputFile.exists()) {
			// FileConverterUtil.convertXLSXToCSV(new File(inputFilePath),
			// outputFile);
			// }
		}
	}
	// End
}
